package com.dylon.seapiweb.shiro.realm;

import com.dylon.seapiweb.exception.user.*;
import com.dylon.seapiweb.service.SysLoginService;
import com.dylon.system.domain.SysUsers;
import com.dylon.system.service.ISysMenuService;
import com.dylon.system.service.ISysRoleService;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.HashSet;
import java.util.Set;


@Log4j2
public class ShiroRealm  extends AuthorizingRealm {

    @Autowired
    private ISysMenuService menuService;
    @Autowired
    private ISysRoleService roleService;
    @Autowired
    private SysLoginService loginService;

    /**
     * 授予角色和权限
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //授权
        log.info("授予角色和权限");
        // 添加权限 和 角色信息
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        // 获取当前登陆用户
        Subject subject = SecurityUtils.getSubject();
        SysUsers user = (SysUsers) subject.getPrincipal();
        if ( user.isAdmin() ) {
            // 超级管理员，添加所有角色、添加所有权限
            authorizationInfo.addRole("*");
            authorizationInfo.addStringPermission("*");
        } else {
            // 普通用户，查询用户的角色，根据角色查询权限
            // 角色列表
            Set<String> roles = new HashSet<String>();
            // 功能列表
            Set<String> menus = new HashSet<String>();

            roles = roleService.selectRoleKeys(user.getUserId());
            menus = menuService.selectPermsByUserId(user.getUserId());
            // 角色加入AuthorizationInfo认证对象
            authorizationInfo.setRoles(roles);
            // 权限加入AuthorizationInfo认证对象
            authorizationInfo.setStringPermissions(menus);

//            List<SysRole> roles = user.getRoles();
//            if (null != roles && roles.size() > 0) {
//                for (SysRole role : roles) {
//                    authorizationInfo.addRole(role.getRoleKey());
//                    // 角色对应的权限数据
//                    List<SysMenu> perms = this.authService.findPermsByRoleId(role
//                            .getId());
//                    if (null != perms && perms.size() > 0) {
//                        // 授权角色下所有权限
//                        for (Permission perm : perms) {
//                            authorizationInfo.addStringPermission(perm
//                                    .getCode());
//                        }
//                    }
//                }
//            }
        }
        return authorizationInfo;
    }

    /**
     * 登录认证
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
            throws AuthenticationException {
        //UsernamePasswordToken用于存放提交的登录信息
        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
        log.info("用户登录认证：验证当前Subject时获取到token为：" +
                ReflectionToStringBuilder.toString(token, ToStringStyle.MULTI_LINE_STYLE));
        String account = token.getUsername();
        String password = "";
        if (token.getPassword() != null) {
            password = new String(token.getPassword());
        }
        // 调用数据层
        SysUsers user = null;
        try {
            user = loginService.login(account, password);
            log.info("用户登录认证！用户信息user：" + user);
        } catch (CaptchaException e) {
            log.info(e);
            throw new AuthenticationException(e.getMessage(), e);
        } catch (UserNotExistsException e) {
            log.info(e);
            throw new UnknownAccountException(e.getMessage(), e);
        } catch (UserPasswordNotMatchException e) {
            log.info(e);
            throw new IncorrectCredentialsException(e.getMessage(), e);
        } catch (UserPasswordRetryLimitExceedException e) {
            log.info(e);
            throw new ExcessiveAttemptsException(e.getMessage(), e);
        } catch (UserBlockedException e) {
            log.info(e);
            throw new LockedAccountException(e.getMessage(), e);
        } catch (RoleBlockedException e) {
            log.info(e);
            throw new LockedAccountException(e.getMessage(), e);
        } catch (Exception e) {
            log.info("对用户[" + account + "]进行登录验证..验证未通过{}", e.getMessage());
            throw new AuthenticationException(e.getMessage(), e);
        }
        // 密码存在
        // 第一个参数 ，登陆后，需要在session保存数据
        // 第二个参数，查询到密码(加密规则要和自定义的HashedCredentialsMatcher中的HashAlgorithmName散列算法一致)
        // 第三个参数 ，realm名字
        return new SimpleAuthenticationInfo(user, DigestUtils.md5Hex(user.getPassWord()), getName());
//        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
//        return info;


    }

    /**
     * 清除所有缓存【实测无效】
     */
    public void clearCachedAuth(){
        this.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
    }

}
